<html><head><META http-equiv="Content-Type" content="text/html; charset=iso-8859-1"><title>Apache Tomcat 7 (7.0.52) - Advanced IO and Tomcat</title><meta name="author" content="Remy Maucherat"><style type="text/css" media="print">
            .noPrint {display: none;}
            td#mainBody {width: 100%;}
        </style><style type="text/css">
            code {background-color:rgb(224,255,255);padding:0 0.1em;}
            code.attributeName, code.propertyName {background-color:transparent;}
        </style><style type="text/css">
            .wrapped-source code { display: block; background-color: transparent; }
            .wrapped-source div { margin: 0 0 0 1.25em; }
            .wrapped-source p { margin: 0 0 0 1.25em; text-indent: -1.25em; }
        </style><style type="text/css">
            p.notice {
                border: 1px solid rgb(255, 0, 0);
                background-color: rgb(238, 238, 238);
                color: rgb(0, 51, 102);
                padding: 0.5em;
                margin: 1em 2em 1em 1em;
            }
        </style></head><body bgcolor="#ffffff" text="#000000" link="#525D76" alink="#525D76" vlink="#525D76"><table border="0" width="100%" cellspacing="0"><!--PAGE HEADER--><tr><td><!--PROJECT LOGO--><a href="http://tomcat.apache.org/"><img src="./images/tomcat.gif" align="right" alt="
      The Apache Tomcat Servlet/JSP Container
    " border="0"></a></td><td><h1><font face="arial,helvetica,sanserif">Apache Tomcat 7</font></h1><font face="arial,helvetica,sanserif">Version 7.0.52, Feb 13 2014</font></td><td><!--APACHE LOGO--><a href="http://www.apache.org/"><img src="./images/asf-logo.gif" align="right" alt="Apache Logo" border="0"></a></td></tr></table><table border="0" width="100%" cellspacing="4"><!--HEADER SEPARATOR--><tr><td colspan="2"><hr noshade size="1"></td></tr><tr><!--LEFT SIDE NAVIGATION--><td width="20%" valign="top" nowrap class="noPrint"><p><strong>Links</strong></p><ul><li><a href="index.html">Docs Home</a></li><li><a href="http://wiki.apache.org/tomcat/FAQ">FAQ</a></li><li><a href="#comments_section">User Comments</a></li></ul><p><strong>User Guide</strong></p><ul><li><a href="introduction.html">1) Introduction</a></li><li><a href="setup.html">2) Setup</a></li><li><a href="appdev/index.html">3) First webapp</a></li><li><a href="deployer-howto.html">4) Deployer</a></li><li><a href="manager-howto.html">5) Manager</a></li><li><a href="realm-howto.html">6) Realms and AAA</a></li><li><a href="security-manager-howto.html">7) Security Manager</a></li><li><a href="jndi-resources-howto.html">8) JNDI Resources</a></li><li><a href="jndi-datasource-examples-howto.html">9) JDBC DataSources</a></li><li><a href="class-loader-howto.html">10) Classloading</a></li><li><a href="jasper-howto.html">11) JSPs</a></li><li><a href="ssl-howto.html">12) SSL</a></li><li><a href="ssi-howto.html">13) SSI</a></li><li><a href="cgi-howto.html">14) CGI</a></li><li><a href="proxy-howto.html">15) Proxy Support</a></li><li><a href="mbeans-descriptor-howto.html">16) MBean Descriptor</a></li><li><a href="default-servlet.html">17) Default Servlet</a></li><li><a href="cluster-howto.html">18) Clustering</a></li><li><a href="balancer-howto.html">19) Load Balancer</a></li><li><a href="connectors.html">20) Connectors</a></li><li><a href="monitoring.html">21) Monitoring and Management</a></li><li><a href="logging.html">22) Logging</a></li><li><a href="apr.html">23) APR/Native</a></li><li><a href="virtual-hosting-howto.html">24) Virtual Hosting</a></li><li><a href="aio.html">25) Advanced IO</a></li><li><a href="extras.html">26) Additional Components</a></li><li><a href="maven-jars.html">27) Mavenized</a></li><li><a href="security-howto.html">28) Security Considerations</a></li><li><a href="windows-service-howto.html">29) Windows Service</a></li><li><a href="windows-auth-howto.html">30) Windows Authentication</a></li><li><a href="jdbc-pool.html">31) Tomcat's JDBC Pool</a></li><li><a href="web-socket-howto.html">32) WebSocket</a></li></ul><p><strong>Reference</strong></p><ul><li><a href="RELEASE-NOTES.txt">Release Notes</a></li><li><a href="config/index.html">Configuration</a></li><li><a href="api/index.html">Tomcat Javadocs</a></li><li><a href="servletapi/index.html">Servlet Javadocs</a></li><li><a href="jspapi/index.html">JSP 2.2 Javadocs</a></li><li><a href="elapi/index.html">EL 2.2 Javadocs</a></li><li><a href="websocketapi/index.html">WebSocket 1.0 Javadocs</a></li><li><a href="http://tomcat.apache.org/connectors-doc/">JK 1.2 Documentation</a></li></ul><p><strong>Apache Tomcat Development</strong></p><ul><li><a href="building.html">Building</a></li><li><a href="changelog.html">Changelog</a></li><li><a href="http://wiki.apache.org/tomcat/TomcatVersions">Status</a></li><li><a href="developers.html">Developers</a></li><li><a href="architecture/index.html">Architecture</a></li><li><a href="funcspecs/index.html">Functional Specs.</a></li><li><a href="tribes/introduction.html">Tribes</a></li></ul></td><!--RIGHT SIDE MAIN BODY--><td width="80%" valign="top" align="left" id="mainBody"><h1>Advanced IO and Tomcat</h1><table border="0" cellspacing="0" cellpadding="2"><tr><td bgcolor="#525D76"><font color="#ffffff" face="arial,helvetica.sanserif"><a name="Table of Contents"><!--()--></a><a name="Table_of_Contents"><strong>Table of Contents</strong></a></font></td></tr><tr><td><blockquote>
<ul><li><a href="#Introduction">Introduction</a></li><li><a href="#Comet_support">Comet support</a><ol><li><a href="#CometEvent">CometEvent</a></li><li><a href="#CometFilter">CometFilter</a></li><li><a href="#Example_code">Example code</a></li><li><a href="#Comet_timeouts">Comet timeouts</a></li></ol></li><li><a href="#Asynchronous_writes">Asynchronous writes</a></li></ul>
</blockquote></td></tr></table><table border="0" cellspacing="0" cellpadding="2"><tr><td bgcolor="#525D76"><font color="#ffffff" face="arial,helvetica.sanserif"><a name="Introduction"><strong>Introduction</strong></a></font></td></tr><tr><td><blockquote>

  <p>
    With usage of APR or NIO APIs as the basis of its connectors, Tomcat is
    able to provide a number of extensions over the regular blocking IO
    as provided with support for the Servlet API.
  </p>

  <p>
    <b>IMPORTANT NOTE: Usage of these features requires using the APR or NIO
    HTTP connectors. The classic java.io HTTP connector and the AJP connectors
    do not support them.</b>
  </p>

  </blockquote></td></tr></table><table border="0" cellspacing="0" cellpadding="2"><tr><td bgcolor="#525D76"><font color="#ffffff" face="arial,helvetica.sanserif"><a name="Comet support"><!--()--></a><a name="Comet_support"><strong>Comet support</strong></a></font></td></tr><tr><td><blockquote>

  <p>
    Comet support allows a servlet to process IO asynchronously, receiving
    events when data is available for reading on the connection (rather than
    always using a blocking read), and writing data back on connections
    asynchronously (most likely responding to some event raised from some
    other source).
  </p>

  <table border="0" cellspacing="0" cellpadding="2"><tr><td bgcolor="#828DA6"><font color="#ffffff" face="arial,helvetica.sanserif"><a name="CometEvent"><strong>CometEvent</strong></a></font></td></tr><tr><td><blockquote>

  <p>
    Servlets which implement the <code>org.apache.catalina.comet.CometProcessor</code>
    interface will have their event method invoked rather than the usual service
    method, according to the event which occurred. The event object gives
    access to the usual request and response objects, which may be used in the
    usual way. The main difference is that those objects remain valid and fully
    functional at any time between processing of the BEGIN event until processing
    an END or ERROR event.
    The following event types exist:
  </p>

  <ul>
  <li>EventType.BEGIN: will be called at the beginning
     of the processing of the connection. It can be used to initialize any relevant
     fields using the request and response objects. Between the end of the processing
     of this event, and the beginning of the processing of the end or error events,
     it is possible to use the response object to write data on the open connection.
     Note that the response object and dependent OutputStream and Writer are still
     not synchronized, so when they are accessed by multiple threads,
     synchronization is mandatory. After processing the initial event, the request
     is considered to be committed.</li>
  <li>EventType.READ: This indicates that input data is available, and that one read can be made
       without blocking. The available and ready methods of the InputStream or
       Reader may be used to determine if there is a risk of blocking: the servlet
       should read while data is reported available. When encountering a read error,
       the servlet should report it by propagating the exception properly. Throwing
       an exception will cause the error event to be invoked, and the connection
       will be closed.
       Alternately, it is also possible to catch any exception, perform clean up
       on any data structure the servlet may be using, and using the close method
       of the event. It is not allowed to attempt reading data from the request
       object outside of the execution of this method.<br>
       On some platforms, like Windows, a client disconnect is indicated by a READ event.
       Reading from the stream may result in -1, an IOException or an EOFException.
       Make sure you properly handle all these three cases.
       If you don't catch the IOException, Tomcat will instantly invoke your event chain with an ERROR as
       it catches the error for you, and you will be notified of the error at that time.
  </li>
  <li>EventType.END: End may be called to end the processing of the request. Fields that have
     been initialized in the begin method should be reset. After this event has
     been processed, the request and response objects, as well as all their dependent
     objects will be recycled and used to process other requests. End will also be
     called when data is available and the end of file is reached on the request input
     (this usually indicates the client has pipelined a request).</li>
  <li>EventType.ERROR: Error will be called by the container in the case where an IO exception
     or a similar unrecoverable error occurs on the connection. Fields that have
     been initialized in the begin method should be reset. After this event has
     been processed, the request and response objects, as well as all their dependent
     objects will be recycled and used to process other requests.</li>
  </ul>

  <p>
    There are some event subtypes which allow finer processing of events (note: some of these
    events require usage of the org.apache.catalina.valves.CometConnectionManagerValve valve):
  </p>

  <ul>
  <li>EventSubType.TIMEOUT: The connection timed out (sub type of ERROR); note that this ERROR
    type is not fatal, and the connection will not be closed unless the servlet uses the close
    method of the event.
  </li>
  <li>EventSubType.CLIENT_DISCONNECT: The client connection was closed (sub type of ERROR).
  </li>
  <li>EventSubType.IOEXCEPTION: An IO exception occurred, such as invalid content, for example,
    an invalid chunk block (sub type of ERROR).
  </li>
  <li>EventSubType.WEBAPP_RELOAD: The web application is being reloaded (sub type of END).
  </li>
  <li>EventSubType.SESSION_END: The servlet ended the session (sub type of END).
  </li>
  </ul>

  <p>
    As described above, the typical lifecycle of a Comet request will consist in a series of
    events such as: BEGIN -&gt; READ -&gt; READ -&gt; READ -&gt; ERROR/TIMEOUT. At any time, the servlet
    may end processing of the request by using the close method of the event object.
  </p>

  </blockquote></td></tr></table>

  <table border="0" cellspacing="0" cellpadding="2"><tr><td bgcolor="#828DA6"><font color="#ffffff" face="arial,helvetica.sanserif"><a name="CometFilter"><strong>CometFilter</strong></a></font></td></tr><tr><td><blockquote>

  <p>
    Similar to regular filters, a filter chain is invoked when comet events are processed.
    These filters should implement the CometFilter interface (which works in the same way as
    the regular Filter interface), and should be declared and mapped in the deployment
    descriptor in the same way as a regular filter. The filter chain when processing an event
    will only include filters which match all the usual mapping rules, and also implement
    the CometFiler interface.
  </p>

  </blockquote></td></tr></table>

  <table border="0" cellspacing="0" cellpadding="2"><tr><td bgcolor="#828DA6"><font color="#ffffff" face="arial,helvetica.sanserif"><a name="Example code"><!--()--></a><a name="Example_code"><strong>Example code</strong></a></font></td></tr><tr><td><blockquote>

  <p>
    The following pseudo code servlet implements asynchronous chat functionality using the API
    described above:
  </p>

  <div align="left"><table cellspacing="4" cellpadding="0" border="0"><tr><td bgcolor="#023264" width="1" height="1"><img src="./images/void.gif" alt="" width="1" height="1" vspace="0" hspace="0" border="0"></td><td bgcolor="#023264" height="1"><img src="./images/void.gif" alt="" width="1" height="1" vspace="0" hspace="0" border="0"></td><td bgcolor="#023264" width="1" height="1"><img src="./images/void.gif" alt="" width="1" height="1" vspace="0" hspace="0" border="0"></td></tr><tr><td bgcolor="#023264" width="1"><img src="./images/void.gif" alt="" width="1" height="1" vspace="0" hspace="0" border="0"></td><td bgcolor="#ffffff" height="1"><pre>
public class ChatServlet
    extends HttpServlet implements CometProcessor {

    protected ArrayList&lt;HttpServletResponse&gt; connections =
        new ArrayList&lt;HttpServletResponse&gt;();
    protected MessageSender messageSender = null;

    public void init() throws ServletException {
        messageSender = new MessageSender();
        Thread messageSenderThread =
            new Thread(messageSender, "MessageSender[" + getServletContext().getContextPath() + "]");
        messageSenderThread.setDaemon(true);
        messageSenderThread.start();
    }

    public void destroy() {
        connections.clear();
        messageSender.stop();
        messageSender = null;
    }

    /**
     * Process the given Comet event.
     *
     * @param event The Comet event that will be processed
     * @throws IOException
     * @throws ServletException
     */
    public void event(CometEvent event)
        throws IOException, ServletException {
        HttpServletRequest request = event.getHttpServletRequest();
        HttpServletResponse response = event.getHttpServletResponse();
        if (event.getEventType() == CometEvent.EventType.BEGIN) {
            log("Begin for session: " + request.getSession(true).getId());
            PrintWriter writer = response.getWriter();
            writer.println("&lt;!doctype html public \"-//w3c//dtd html 4.0 transitional//en\"&gt;");
            writer.println("&lt;head&gt;&lt;title&gt;JSP Chat&lt;/title&gt;&lt;/head&gt;&lt;body bgcolor=\"#FFFFFF\"&gt;");
            writer.flush();
            synchronized(connections) {
                connections.add(response);
            }
        } else if (event.getEventType() == CometEvent.EventType.ERROR) {
            log("Error for session: " + request.getSession(true).getId());
            synchronized(connections) {
                connections.remove(response);
            }
            event.close();
        } else if (event.getEventType() == CometEvent.EventType.END) {
            log("End for session: " + request.getSession(true).getId());
            synchronized(connections) {
                connections.remove(response);
            }
            PrintWriter writer = response.getWriter();
            writer.println("&lt;/body&gt;&lt;/html&gt;");
            event.close();
        } else if (event.getEventType() == CometEvent.EventType.READ) {
            InputStream is = request.getInputStream();
            byte[] buf = new byte[512];
            do {
                int n = is.read(buf); //can throw an IOException
                if (n &gt; 0) {
                    log("Read " + n + " bytes: " + new String(buf, 0, n)
                            + " for session: " + request.getSession(true).getId());
                } else if (n &lt; 0) {
                    error(event, request, response);
                    return;
                }
            } while (is.available() &gt; 0);
        }
    }

    public class MessageSender implements Runnable {

        protected boolean running = true;
        protected ArrayList&lt;String&gt; messages = new ArrayList&lt;String&gt;();

        public MessageSender() {
        }

        public void stop() {
            running = false;
        }

        /**
         * Add message for sending.
         */
        public void send(String user, String message) {
            synchronized (messages) {
                messages.add("[" + user + "]: " + message);
                messages.notify();
            }
        }

        public void run() {

            while (running) {

                if (messages.size() == 0) {
                    try {
                        synchronized (messages) {
                            messages.wait();
                        }
                    } catch (InterruptedException e) {
                        // Ignore
                    }
                }

                synchronized (connections) {
                    String[] pendingMessages = null;
                    synchronized (messages) {
                        pendingMessages = messages.toArray(new String[0]);
                        messages.clear();
                    }
                    // Send any pending message on all the open connections
                    for (int i = 0; i &lt; connections.size(); i++) {
                        try {
                            PrintWriter writer = connections.get(i).getWriter();
                            for (int j = 0; j &lt; pendingMessages.length; j++) {
                                writer.println(pendingMessages[j] + "&lt;br&gt;");
                            }
                            writer.flush();
                        } catch (IOException e) {
                            log("IOExeption sending message", e);
                        }
                    }
                }

            }

        }

    }

}
  </pre></td><td bgcolor="#023264" width="1"><img src="./images/void.gif" alt="" width="1" height="1" vspace="0" hspace="0" border="0"></td></tr><tr><td bgcolor="#023264" width="1" height="1"><img src="./images/void.gif" alt="" width="1" height="1" vspace="0" hspace="0" border="0"></td><td bgcolor="#023264" height="1"><img src="./images/void.gif" alt="" width="1" height="1" vspace="0" hspace="0" border="0"></td><td bgcolor="#023264" width="1" height="1"><img src="./images/void.gif" alt="" width="1" height="1" vspace="0" hspace="0" border="0"></td></tr></table></div>

  </blockquote></td></tr></table>
  <table border="0" cellspacing="0" cellpadding="2"><tr><td bgcolor="#828DA6"><font color="#ffffff" face="arial,helvetica.sanserif"><a name="Comet timeouts"><!--()--></a><a name="Comet_timeouts"><strong>Comet timeouts</strong></a></font></td></tr><tr><td><blockquote>
    <p>If you are using the NIO connector, you can set individual timeouts for your different comet connections.
       To set a timeout, simply set a request attribute like the following code shows:
       <div align="left"><table cellspacing="4" cellpadding="0" border="0"><tr><td bgcolor="#023264" width="1" height="1"><img src="./images/void.gif" alt="" width="1" height="1" vspace="0" hspace="0" border="0"></td><td bgcolor="#023264" height="1"><img src="./images/void.gif" alt="" width="1" height="1" vspace="0" hspace="0" border="0"></td><td bgcolor="#023264" width="1" height="1"><img src="./images/void.gif" alt="" width="1" height="1" vspace="0" hspace="0" border="0"></td></tr><tr><td bgcolor="#023264" width="1"><img src="./images/void.gif" alt="" width="1" height="1" vspace="0" hspace="0" border="0"></td><td bgcolor="#ffffff" height="1"><pre>CometEvent event.... event.setTimeout(30*1000);</pre></td><td bgcolor="#023264" width="1"><img src="./images/void.gif" alt="" width="1" height="1" vspace="0" hspace="0" border="0"></td></tr><tr><td bgcolor="#023264" width="1" height="1"><img src="./images/void.gif" alt="" width="1" height="1" vspace="0" hspace="0" border="0"></td><td bgcolor="#023264" height="1"><img src="./images/void.gif" alt="" width="1" height="1" vspace="0" hspace="0" border="0"></td><td bgcolor="#023264" width="1" height="1"><img src="./images/void.gif" alt="" width="1" height="1" vspace="0" hspace="0" border="0"></td></tr></table></div> or
       <div align="left"><table cellspacing="4" cellpadding="0" border="0"><tr><td bgcolor="#023264" width="1" height="1"><img src="./images/void.gif" alt="" width="1" height="1" vspace="0" hspace="0" border="0"></td><td bgcolor="#023264" height="1"><img src="./images/void.gif" alt="" width="1" height="1" vspace="0" hspace="0" border="0"></td><td bgcolor="#023264" width="1" height="1"><img src="./images/void.gif" alt="" width="1" height="1" vspace="0" hspace="0" border="0"></td></tr><tr><td bgcolor="#023264" width="1"><img src="./images/void.gif" alt="" width="1" height="1" vspace="0" hspace="0" border="0"></td><td bgcolor="#ffffff" height="1"><pre>event.getHttpServletRequest().setAttribute("org.apache.tomcat.comet.timeout", new Integer(30 * 1000));</pre></td><td bgcolor="#023264" width="1"><img src="./images/void.gif" alt="" width="1" height="1" vspace="0" hspace="0" border="0"></td></tr><tr><td bgcolor="#023264" width="1" height="1"><img src="./images/void.gif" alt="" width="1" height="1" vspace="0" hspace="0" border="0"></td><td bgcolor="#023264" height="1"><img src="./images/void.gif" alt="" width="1" height="1" vspace="0" hspace="0" border="0"></td><td bgcolor="#023264" width="1" height="1"><img src="./images/void.gif" alt="" width="1" height="1" vspace="0" hspace="0" border="0"></td></tr></table></div>
       This sets the timeout to 30 seconds.
       Important note: in order to set this timeout, it has to be done on the <code>BEGIN</code> event.
       The default value is <code>soTimeout</code>
    </p>
    <p>If you are using the APR connector, all Comet connections will have the same timeout value. It is <code>soTimeout*50</code>
    </p>
  </blockquote></td></tr></table>

  </blockquote></td></tr></table><table border="0" cellspacing="0" cellpadding="2"><tr><td bgcolor="#525D76"><font color="#ffffff" face="arial,helvetica.sanserif"><a name="Asynchronous writes"><!--()--></a><a name="Asynchronous_writes"><strong>Asynchronous writes</strong></a></font></td></tr><tr><td><blockquote>

  <p>
    When APR or NIO is enabled, Tomcat supports using sendfile to send large static files.
    These writes, as soon as the system load increases, will be performed
    asynchronously in the most efficient way. Instead of sending a large response using
    blocking writes, it is possible to write content to a static file, and write it
    using a sendfile code. A caching valve could take advantage of this to cache the
    response data in a file rather than store it in memory. Sendfile support is
    available if the request attribute <code>org.apache.tomcat.sendfile.support</code>
    is set to <code>Boolean.TRUE</code>.
  </p>

  <p>
    Any servlet can instruct Tomcat to perform a sendfile call by setting the appropriate
    request attributes. It is also necessary to correctly set the content length
    for the response. When using sendfile, it is best to ensure that neither the
    request or response have been wrapped, since as the response body will be sent later
    by the connector itself, it cannot be filtered. Other than setting the 3 needed
    request attributes, the servlet should not send any response data, but it may use
    any method which will result in modifying the response header (like setting cookies).
  </p>

  <ul>
  <li><code>org.apache.tomcat.sendfile.filename</code>: Canonical filename of the file which will be sent as
      a String</li>
  <li><code>org.apache.tomcat.sendfile.start</code>: Start offset as a Long</li>
  <li><code>org.apache.tomcat.sendfile.end</code>: End offset as a Long</li>
  </ul>

  </blockquote></td></tr></table></td></tr><tr class="noPrint"><td width="20%" valign="top" nowrap class="noPrint"></td><td width="80%" valign="top" align="left"><table border="0" cellspacing="0" cellpadding="2"><tr><td bgcolor="#525D76"><font color="#ffffff" face="arial,helvetica.sanserif"><a name="comments_section" id="comments_section"><strong>Comments</strong></a></font></td></tr><tr><td><blockquote><p class="notice"><strong>Notice: </strong>This comments section collects your suggestions
              on improving documentation for Apache Tomcat.<br><br>
              If you have trouble and need help, read
              <a href="http://tomcat.apache.org/findhelp.html">Find Help</a> page
              and ask your question on the tomcat-users
              <a href="http://tomcat.apache.org/lists.html">mailing list</a>.
              Do not ask such questions here. This is not a Q&amp;A section.<br><br>
              The Apache Comments System is explained <a href="./comments.html">here</a>.
              Comments may be removed by our moderators if they are either
              implemented or considered invalid/off-topic.</p><script type="text/javascript"><!--//--><![CDATA[//><!--
              var comments_shortname = 'tomcat';
              var comments_identifier = 'http://tomcat.apache.org/tomcat-7.0-doc/aio.html';
              (function(w, d) {
                  if (w.location.hostname.toLowerCase() == "tomcat.apache.org") {
                      d.write('<div id="comments_thread"><\/div>');
                      var s = d.createElement('script');
                      s.type = 'text/javascript';
                      s.async = true;
                      s.src = 'https://comments.apache.org/show_comments.lua?site=' + comments_shortname + '&page=' + comments_identifier;
                      (d.getElementsByTagName('head')[0] || d.getElementsByTagName('body')[0]).appendChild(s);
                  }
                  else {
                      d.write('<div id="comments_thread"><strong>Comments are disabled for this page at the moment.<\/strong><\/div>');
                  }
              })(window, document);
              //--><!]]></script></blockquote></td></tr></table></td></tr><!--FOOTER SEPARATOR--><tr><td colspan="2"><hr noshade size="1"></td></tr><!--PAGE FOOTER--><tr><td colspan="2"><div align="center"><font color="#525D76" size="-1"><em>
        Copyright &copy; 1999-2014, Apache Software Foundation
        </em></font></div></td></tr></table></body></html>